package com.itheima.health.security;

import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;

/**
 * @author ：张致玮
 * @description ：权限过滤器
 */
@Slf4j
@WebFilter(urlPatterns = "/*")
public class HealthSecurityFilter implements Filter {
	@Autowired
	RedisTemplate redisTemplate;


	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
						 FilterChain filterChain) throws IOException, ServletException {
		//拦截所有请求
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		//放行语句
//        filterChain.doFilter(request,response);

//        //1、判断当前路径是否是无需登陆url（白名单【从redis中获取】）匹配成功直接访问，反之走第二步
//        //2、判断是已登录，如果已登录判断是否是需要授权的uri（从redis中获取）匹配成功不需要授权，放行，反之走第三步
//        //3、判断当前uri是否在用户的权限中，如果存在则放行，反之告知“未授权”
//
//
//        // 1.获取URI
//        String uri = request.getRequestURI();
//        log.info("[权限检查过滤器...],当前uri:{}", uri);
//        filterChain.doFilter(request, response);
//        List<String> baimingdan = new ArrayList<>();
//        baimingdan.add("/user/login");
//
		String uri = request.getRequestURI();
		log.info("权限检查过滤器，当前url：", uri);

		boolean isNotLoginAccess = checkURI(uri);
		if (isNotLoginAccess) {// true 是白名单 放行
			log.info("是白名单");
			filterChain.doFilter(request, response);
			return;
		}
		log.info("不是白名单，需要登录校验");
		//获取user
		User user = (User) request.getSession().getAttribute("user");
		if (null != user) {
			//登录了
			log.info("登录后 查看该用户是否有访问该资源的权限");
			boolean isLoginAuth = checkLoginAuthURI(uri, user);
			//判断是否有权限
			if (isLoginAuth){
				log.info("登录之后，用户有权限 放行");
				filterChain.doFilter(request,response);
			}else {
				//没有权限
				response.setContentType("application/json;charset=utf-8");
				Result result = new Result(false, "无权访问");
				String json = JSON.toJSONString(result);
				response.getWriter().write(json);
			}
		} else {
			//没有登录
			response.setContentType("application/json;charset=utf-8");
			Result result = new Result(false, "请重新登录");
			String json = JSON.toJSONString(result);
			response.getWriter().write(json);
		}


//
//
//        if (baimingdan.contains(uri)) {
//            filterChain.doFilter(request, response);
//        } else {
//            request.setAttribute("login_msg", "您尚未登录，请登录");
//            //重定向
//            servletRequest.getRequestDispatcher("/pages/login.html").forward(request, response);
//        }

//		2. 每次请求通过，对当前访问的URI进行匹配
		//		1. 先匹配是否无需登录即可访问
		//		1. 匹配，放行
//			2. 不匹配，需要登录访问
//		2. 再匹配登录后，是否需要授权即可访问
//			1. 不需要授权，放行
//		2. 需要授权，判断当前用户的权限列表是否匹配
		//		1. 不匹配，告知“未授权”
		//		2. 匹配，允许通过
	}

	// 设置白名单
	String[] auths = new String[]{
			"/user/login",
			"/user/logout",
			"/common/**",
			"/mobile/**" //移动端无需登录
	};

	// 定义登录后  需要授权才能访问的URI 集合
	//  /checkitem/delete   对应一个权限关键字  CHECKITEM_DELETE
	//  /checkgroup/delete  对应一个权限关键字  CHECKGROUP_DELETE
	//  /setmeal/delete                        SETMEAL_DELETE
	//  /report/**                             REPORT_VIEW
	//   定义 存储 uri 权限校验路径  和  权限校验关键字  集合
	//             String           String
	private Map<String, String> loginAuthUrlMap = new HashMap<>();

	//  需要设置权限列表 以及权限关键字

	private void initAutlUrlMap() {
//      loginAuthUrlMap.put("","");
		// 初始化这里 完成  map初始化
		// 初始化  哪些路径 需要  哪些权限
		//  解释  你如果访问的路径是 检查项的删除  必须要有 CHECKITEM_DELETE 的权限!!
		loginAuthUrlMap.put("/checkitem/add","CHECKITEM_ADD");//新增检查项
		loginAuthUrlMap.put("/checkitem/delete", "CHECKITEM_DELETE");//删除检查项
		loginAuthUrlMap.put("/checkitem/edit","CHECKITEM_EDIT");//编辑检查项
		loginAuthUrlMap.put("/checkitem/findById","CHECKITEM_QUERY");//根据id查询检查项
		loginAuthUrlMap.put("/checkitem/findAll","CHECKITEM_QUERY");//查询所有检查项
		loginAuthUrlMap.put("/checkgroup/add","CHECKGROUP_ADD");//新增检查组
		loginAuthUrlMap.put("/checkgroup/deleteCheckGroupitemById","CHECKGROUP_DELETE");//删除检查组
		//todo
		loginAuthUrlMap.put("/checkgroup/","CHECKGROUP_EDIT");//编辑检查组
		loginAuthUrlMap.put("/checkgroup/","CHECKGROUP_QUERY");//查询检查组
		loginAuthUrlMap.put("/setmeal/","SETMEAL_ADD");//新增套餐
		loginAuthUrlMap.put("/setmeal/","SETMEAL_DELETE");//删除套餐
		loginAuthUrlMap.put("/setmeal/","SETMEAL_EDIT");//编辑套餐
		loginAuthUrlMap.put("/setmeal/","SETMEAL_QUERY");//查询套餐
		loginAuthUrlMap.put("","ORDERSETTING");//预约设置
		loginAuthUrlMap.put("","MENU_ADD");//新增菜单
		loginAuthUrlMap.put("","MENU_DELETE");//删除菜单
		loginAuthUrlMap.put("","MENU_EDIT");//编辑菜单
		loginAuthUrlMap.put("","MENU_QUERY");//查询菜单
		loginAuthUrlMap.put("","ROLE_ADD");//新增角色
		loginAuthUrlMap.put("","ROLE_DELETE");//删除角色
		loginAuthUrlMap.put("","ROLE_EDIT");//编辑角色
		loginAuthUrlMap.put("","ROLE_QUERY");//查询角色
		loginAuthUrlMap.put("","USER_ADD");//新增用户
		loginAuthUrlMap.put("","USER_DELETE");//删除用户
		loginAuthUrlMap.put("","USER_EDIT");//编辑用户
		loginAuthUrlMap.put("","USER_QUERY");//查询用户
		loginAuthUrlMap.put("/report/**", "REPORT_VIEW");//查看统计报表

	}

	// 判断需不需要登录才能访问 的资源
	private boolean checkURI(String reqUri) {
		//路径匹配器
		AntPathMatcher pathMatcher = new AntPathMatcher();
		//遍历数组
		// url 白名单规则    reqUri 请求的路径
		for (String url : auths) {
			if (pathMatcher.match(url, reqUri)) {
				log.info("[权限过滤器,匹配是白名单:uri:{}]", reqUri);
				return true;
			}
		}

		return false;//需要登录访问
	}

	//    再匹配登录后，是否需要授权即可访问
	// 判断 登录后  该资源 是否需要进行权限校验后访问
	//   如果 不需要 返回true     如果需要 且权限匹配上了 返回true
	//   如果 不匹配 说明 没有权限
	private boolean checkLoginAuthURI(String reqUri, User user) {
		//查询到用户的所有权限
		//根路径具备的权限进行比对

		//路径匹配器
		AntPathMatcher matcher = new AntPathMatcher();
		// 1: 匹配 reqUri 是不是 在 哪个map集合 匹配规则中
		// 如果不是就 返回true  说明谁都具备访问的权限
		Set<String> keySet = loginAuthUrlMap.keySet();
		//  keySet  具有权限路径规则
		String currKeyUrl = null; //用它来接收 匹配出来的 路径规则
		for (String urlKey : keySet) {
			// 键路径 匹配规则   reqUri匹配
			if (matcher.match(urlKey, reqUri)) {
				//true 说明 这个路径需要权限访问
				currKeyUrl = urlKey;
			}
		}
		if (currKeyUrl == null) {
			//说明该路径不需要权限访问  谁都访问权限
			log.info("当前该路径不需要权限校验，谁都有权限...");
			return true;
		}
		//走到这里说明 currKeyUrl !=null  该路径需要进行权限校验
		// 取出权限关键字
		String authKeyword = loginAuthUrlMap.get(currKeyUrl);
		log.info("[权限检查过滤器],当前用户访问的uri需要授权，currKeyUrl:" +
				"{},keyWord:{}",currKeyUrl,authKeyword);
		log.info("[权限检查过滤器],当前用户信息：user:{}",user);
		// 判断当前用户是否拥有此权限
		// 查看用户都有那些角色   角色都有哪些权限
		// 遍历该用户的所有权限   跟  能通过的权限关键字 进行比较  ok 就具备资源访问权限
		Set<Role> roles = user.getRoles();
		for (Role role : roles){
			Set<Permission> permissions = role.getPermissions();
			for (Permission permission : permissions){
				if (permission.getKeyword().equals(authKeyword)){
					//匹配成功
					log.info("[权限检查过滤器],当前用户匹配权限，允许方式，通过");
					return true;
				}
			}
		}
		log.info("[权限检查过滤器],当前用户匹配权限不匹配，未通过");
		return false;
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		//初始化无需登录的URI列表
//		redisTemplate.opsForValue().set();
		//初始化需要权限匹配的URI集合
		initAutlUrlMap();
	}


	@Override
	public void destroy() {

	}

}